using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using QntPlatform.BinanceApi;
using QntPlatform.Strategy.CmdCtrl;
using QntPlatform.Strategy.Utility;

namespace QntPlatform.Strategy.S2
{
    /*
    策略：系统参数、用户参数，用户命令，策略脚本、日志
    */
    public abstract class PeriodTrandBase<T> : StrategyBase2 where T : TradeInfo
    {
        [ArgInfo(Remark = "周期")]
        public int NowPeriod { get; protected set; }
        public PeriodTrandBase() {
            NowPeriod = 60;
        }
        protected virtual bool IsCheckTrend { get; } = true;
        //public bool IsEnd { get; protected set; } = false;
        public int GetTrend()
        {
            //user,交易所，交易对，交易周期，趋势
            var key=$"{Exchange.Name}:{Exchange.Currency}:{NowPeriod}";
           var valStr= FApiClent.GetUserData(key);
            if (!string.IsNullOrWhiteSpace(valStr))
            {
                return int.Parse(valStr);
            }
            return 0;
        }
        public abstract void Execute(T info);
    
        public override void OnExit(Exception ex)
        {

            SysFun.CommandEvent -= SysFun_CommandEvent;
            base.OnExit(ex);
        }
        public override void MainFun()
        {
            SysFun.CommandEvent += SysFun_CommandEvent;
        }
        private void SysFun_CommandEvent(object sender, string e)
        {
            //命令格式1cmdName:val,2cmdName:{}

            //var cmd = CmdFun.GetCmdKV(e);
            var info = SysFun.ParseTo<T>(e);
            if (info.Period != NowPeriod)
            {
                Log.Debug("不同周期，忽略命令:",e);
                return;
            }
            if (info.IsLong==null)
            {
                throw new ArgumentException($"策略周期错误或交易方向为空,NowPeriod:{NowPeriod},cmd:"+e);
            }
            if (IsCheckTrend)
            {
                var trend = GetTrend();
                int cmdTrandNum = info.IsLong.Value ? 1 : -1;
                if (!(trend == cmdTrandNum || trend == 2))
                {
                    Log.Debug("趋势不符，忽略交易命令", new { CmdStr = e, trend });
                    return;
                }
            }
            Execute(info);
        }

    }

        public class TradeInfo{
             public int? Period { get; set; }
            public bool? IsLong { get; set; }
        }
 
    public abstract class StrategyBase2:IStrategy
    {
        
        bool isSysInit = false;
        public bool IsEnd { get; protected set; } = false;
        public StrategyBase2(){
           Log= LogManager.GetLogger(GetType().Name+"-"+GetHashCode());
        }
        public void SysInit(IExchange exchange, ISysFun sysFun, ISysApi sysApi, ITAFun ta, IReadOnlyDictionary<string, string> args,ILog log=null)
        {
            if (isSysInit)
                throw new MethodAccessException("重复初始化");
            isSysInit = true;
            SysFun = sysFun;
            SysApi = sysApi;
            TA = ta;
            Exchange = exchange;
            Args=args;
            if(Args!=null)
            InitStrategyArgs();
            if(log!=null)
            Log=log;
        }
        //protected abstract void InitStrategyArgs();
        public ISysFun SysFun { get; private set; }
        public ISysApi SysApi { get; private set; }
        public ITAFun TA { get; private set; }
        public IExchange Exchange { get; private set; }
        public ArgInfo[] ArgInfos{get;protected set;}
        public IReadOnlyDictionary<string, string> Args{get;private set;}
       public ILog Log{get;private set;}
    abstract public void MainFun();
        public virtual void Init() { return; }
        public virtual void OnExit(Exception ex = null)
        {
            IsEnd = true;
            Console.WriteLine(ex);
        }
        public virtual ArgInfo Remark { get {
                var t = GetType();
              var info=  t.GetCustomAttribute<ArgInfo>();
                if (string.IsNullOrWhiteSpace(info.Name))
                {
                    info.Name = t.Name;
                }
                return info;
            } }
        protected virtual void InitStrategyArgs()
        {
            var pops = GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
            //ArgInfos
            foreach (var item in Args)
            {
                    if (!string.IsNullOrWhiteSpace(item.Value))
                    {
                        var pop = pops.FirstOrDefault(p => p.Name == item.Key);
                        if (pop != null)
                        {

                            var val = System.Convert.ChangeType(item.Value, pop.PropertyType);
                            pop.SetValue(this, val);
                        }
                    }
           
            }
        }
        public ArgInfo[] GetArgInfosByAttr()
        {
            var type = GetType();   
            var infos = new List<ArgInfo>();
            // var finfos=type.GetFields();
            // foreach (var item in finfos)
            // {
            //    var info= item.GetCustomAttribute<ArgInfo>();
            //    if(info==null)
            //    continue;
            //    if (string.IsNullOrWhiteSpace(info.Name))
            //     {
            //         info.Name = item.Name;
            //     }
            //     if (string.IsNullOrWhiteSpace(info.Type))
            //     {
            //         info.Type = item.FieldType.Name;
            //     }
            //     if (string.IsNullOrWhiteSpace(info.DefaultVal))
            //     {
            //         info.DefaultVal = item.GetValue(this) + "";
            //     }
            //     infos.Add(info);
            // }
            
            var pops = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
            //var infos = new List<ArgInfo>();
            foreach (var item in pops)
            {
                var info = item.GetCustomAttribute<ArgInfo>();
                if (info == null)
                    continue;
                if (string.IsNullOrWhiteSpace(info.Name))
                {
                    info.Name = item.Name;
                }
                if (string.IsNullOrWhiteSpace(info.Type))
                {
                    info.Type = item.PropertyType.Name;
                }
                if (string.IsNullOrWhiteSpace(info.DefaultVal))
                {
                    info.DefaultVal = item.GetValue(this) + "";
                }
                infos.Add(info);
            }
            
            return infos.ToArray();
        }

    }
    [AttributeUsage(AttributeTargets.All,AllowMultiple=true)]
    public class ArgInfo: Attribute
    {
        public string Name { get; set; }
        public string Remark { get; set; }
        public string Type { get; set; }
        public int Order { get; set; }
        public string CheckInfo { get; set; }
        public string DefaultVal { get; set; }
    }
}
